/*
 *  This file is part of Bracket Properties
 *  Copyright 2011 David R. Smith
 *
 */

package org.dave.bracket.properties;

import java.util.ArrayList;
import java.util.List;
/**
 * Populate a Properties object. Parser is a thread-safe one use object. The list of
 * tokens normally comes from a PropertiesLexer.
 * 
 * @author Dave
 * @see PropertiesLexer
 */
public class PropertiesParser {
	
	final List<PropertiesToken> tokens;
	int index;
	final Properties properties;

	public PropertiesParser(List<PropertiesToken> tokens, Properties properties) {
		super();
		this.tokens = tokens;
		this.properties = properties;
	}
	
	public PropertiesParser(List<PropertiesToken> tokens) {
		super();
		this.tokens = tokens;
		this.properties = new PropertiesImpl();
	}
	
	public synchronized void parse(){
		String key = null;
		ValueModel value = new ValueModel();
		while(index<tokens.size()){
			PropertiesToken t = la(0);
			//System.out.println(t);
			
			if(t.type==PropertiesTokenType.COMMENT){
				value.addComment(t.text);
				index++;
				index++; // consume the line break on the comment
				continue;
			}
			
			// consume an empty line
			if(t.type==PropertiesTokenType.NATURAL_LINE_BREAK){
				index++;
				continue;
			}
			
			if(t.type==PropertiesTokenType.KEY){
				key = t.text;
				PropertiesToken sep = la(1);
				value.setSeparator(sep.text.charAt(0));
				PropertiesToken val = la(2);
				if(val.type==PropertiesTokenType.NATURAL_LINE_BREAK){
					// key with no value
					value.addValue("");
					properties.getPropertyMap().put(key, value);
					index+=3; // consumes the line break
					value = new ValueModel();
					continue;
				}
				
				value.addValue(val.text);
				
				index+=3;
				
				PropertiesToken lineEnd = la(0);
				if(lineEnd.type==PropertiesTokenType.LOGICAL_LINE_BREAK){
					List<String> found = scanAheadForLogicalValues();
					for(String s:found) value.addValue(s);
					index+=(found.size()*2);//consume all additional logical values and their seps
					properties.getPropertyMap().put(key, value);
					value = new ValueModel();
					continue;
				}else if(lineEnd.type==PropertiesTokenType.NATURAL_LINE_BREAK){
					properties.getPropertyMap().put(key, value);
					value = new ValueModel();
					continue;
				}
			}
			
			index++;
		}
	}
	
	private synchronized PropertiesToken la(int amt){
		try{
			PropertiesToken tok = tokens.get(index+amt);
		//	System.out.println("la"+(amt)+"="+tok+" at index "+(index+amt));
			return tok;
		}catch(IndexOutOfBoundsException x){
			return null;
		}
	}
	
	private synchronized List<String> scanAheadForLogicalValues(){
		List<String> list = new ArrayList<String>();
		
		while(true){
			PropertiesToken la0 = la(0);
			PropertiesToken la1 = la(1);
			if(	la0!= null
				&& la0.type==PropertiesTokenType.LOGICAL_LINE_BREAK
				&& la1 != null
				&& la1.type==PropertiesTokenType.VALUE){
					String val = la1.text;
					list.add(val);
				    index+=2;
			}else{
				return list;
			}
		}
	}

	public Properties getProperties() {
		return properties;
	}
	
}
